import { ConditionBuilder } from './ConditionBuilder';
import { SqlExecutor } from './types';
import { 
  FieldSelection, 
  JoinCondition, 
  OrderBy, 
  OrderDirection, 
  ORDER_DIRECTION,
  QueryResult, 
  SingleResult, 
  SqlBuildResult, 
  SqlBuilderExtensions, 
  SqlOperationType, 
  SQL_OPERATION_TYPE,
  TableEntityMapping,
  JoinType,
  JOIN_TYPE
} from './types';

/**
 * 查询构建器
 * 用于构建SELECT SQL语句
 */
export class SelectBuilder<T> extends ConditionBuilder<T> {
  /** 查询字段列表 */
  private fields: string[] = ['*'];
  
  /** 分组字段列表 */
  private groupByFields: string[] = [];
  
  /** 排序条件列表 */
  private orderByConditions: OrderBy[] = [];
  
  /** 联接条件列表 */
  private joinConditions: JoinCondition[] = [];
  
  /** 限制数量 */
  private limitValue?: number;
  
  /** 偏移数量 */
  private offsetValue?: number;
  
  /** 是否获取单个结果 */
  private singleResult: boolean = false;
  
  /** 是否获取总数 */
  private countMode: boolean = false;
  
  /** 是否去重 */
  private distinctMode: boolean = false;
  
  /** 映射函数 */
  private mapFunction?: (row: Record<string, any>) => any;

  /** 表名 */
  private tableName: string;

  /** 实体映射信息 */
  private entityMapping?: TableEntityMapping;

  /** SQL操作类型 */
  private operationType: SqlOperationType = SQL_OPERATION_TYPE.SELECT;

  /**
   * 构造函数
   * @param tableName 表名
   * @param tableAlias 表别名（可选，默认为't'）
   * @param entityMapping 实体映射信息（可选）
   * @param extensions SQL构建器扩展（可选）
   */
  constructor(
    tableName: string,
    tableAlias?: string,
    entityMapping?: TableEntityMapping,
    extensions?: SqlBuilderExtensions
  ) {
    super(tableAlias || 't', extensions);
    this.tableName = tableName;
    this.entityMapping = entityMapping;
  }

  /**
   * 克隆当前构建器
   */
  protected clone(): SelectBuilder<T> {
    const clone = new SelectBuilder<T>(
      this.tableName,
      this.tableAlias,
      this.entityMapping,
      this.extensions
    );
    
    clone.conditions = [...this.conditions];
    clone.parameters = { ...this.parameters };
    clone.paramCounter = this.paramCounter;
    clone.fields = [...this.fields];
    clone.groupByFields = [...this.groupByFields];
    clone.orderByConditions = [...this.orderByConditions];
    clone.joinConditions = [...this.joinConditions];
    clone.limitValue = this.limitValue;
    clone.offsetValue = this.offsetValue;
    clone.singleResult = this.singleResult;
    clone.countMode = this.countMode;
    clone.distinctMode = this.distinctMode;
    clone.mapFunction = this.mapFunction;
    
    return clone;
  }

  /**
   * 设置查询字段
   * @param fields 字段列表或*
   */
  public select(fields: FieldSelection<T>): this {
    if (fields === '*') {
      this.fields = ['*'];
    } else if (Array.isArray(fields)) {
      this.fields = fields.map(field => this.processFieldName(field as string));
    }
    
    return this;
  }

  /**
   * 启用去重模式
   */
  public distinct(): this {
    this.distinctMode = true;
    return this;
  }

  /**
   * 添加联接条件
   * @param joinCondition 联接条件
   */
  public join(joinCondition: JoinCondition): this {
    this.joinConditions.push(joinCondition);
    return this;
  }

  /**
   * 添加LEFT JOIN
   * @param table 表名
   * @param aliasOrConditionCallback 表别名或联接条件回调
   * @param onConditionCallbackOrEntityMapping 联接条件回调或实体映射信息
   * @param entityMapping 实体映射信息（可选）
   */
  public leftJoin<U>(
    table: string,
    aliasOrConditionCallback: string | ((builder: ConditionBuilder<U>) => void),
    onConditionCallbackOrEntityMapping?: ((builder: ConditionBuilder<U>) => void) | TableEntityMapping,
    entityMapping?: TableEntityMapping
  ): this {
    let alias: string;
    let onConditionCallback: (builder: ConditionBuilder<U>) => void;
    let actualEntityMapping: TableEntityMapping | undefined;

    // 处理多态参数
    if (typeof aliasOrConditionCallback === 'function') {
      // 如果第二个参数是函数，则没有提供别名，需要自动生成
      // 计算当前JOIN数量，生成t1, t2...格式的别名
      alias = `t${this.joinConditions.length + 1}`;
      onConditionCallback = aliasOrConditionCallback;
      actualEntityMapping = onConditionCallbackOrEntityMapping as TableEntityMapping;
    } else {
      // 如果第二个参数是字符串，表示提供了别名
      alias = aliasOrConditionCallback;
      onConditionCallback = onConditionCallbackOrEntityMapping as (builder: ConditionBuilder<U>) => void;
      actualEntityMapping = entityMapping;
    }

    // 创建临时条件构建器
    const conditionBuilder = new ConditionBuilder<U>(alias, this.extensions);
    
    // 执行回调以获取条件
    onConditionCallback(conditionBuilder);
    
    // 创建联接条件
    const joinCondition: JoinCondition = {
      type: JOIN_TYPE.LEFT,
      table,
      alias,
      on: conditionBuilder.getConditions(),
      entityMapping: actualEntityMapping
    };
    
    // 添加联接条件
    this.joinConditions.push(joinCondition);
    
    // 添加参数
    Object.assign(this.parameters, conditionBuilder.getParameters());
    
    return this;
  }

  /**
   * 添加INNER JOIN
   * @param table 表名
   * @param aliasOrConditionCallback 表别名或联接条件回调
   * @param onConditionCallbackOrEntityMapping 联接条件回调或实体映射信息
   * @param entityMapping 实体映射信息（可选）
   */
  public innerJoin<U>(
    table: string,
    aliasOrConditionCallback: string | ((builder: ConditionBuilder<U>) => void),
    onConditionCallbackOrEntityMapping?: ((builder: ConditionBuilder<U>) => void) | TableEntityMapping,
    entityMapping?: TableEntityMapping
  ): this {
    let alias: string;
    let onConditionCallback: (builder: ConditionBuilder<U>) => void;
    let actualEntityMapping: TableEntityMapping | undefined;

    // 处理多态参数
    if (typeof aliasOrConditionCallback === 'function') {
      // 如果第二个参数是函数，则没有提供别名，需要自动生成
      // 计算当前JOIN数量，生成t1, t2...格式的别名
      alias = `t${this.joinConditions.length + 1}`;
      onConditionCallback = aliasOrConditionCallback;
      actualEntityMapping = onConditionCallbackOrEntityMapping as TableEntityMapping;
    } else {
      // 如果第二个参数是字符串，表示提供了别名
      alias = aliasOrConditionCallback;
      onConditionCallback = onConditionCallbackOrEntityMapping as (builder: ConditionBuilder<U>) => void;
      actualEntityMapping = entityMapping;
    }
    
    // 创建临时条件构建器
    const conditionBuilder = new ConditionBuilder<U>(alias, this.extensions);
    
    // 执行回调以获取条件
    onConditionCallback(conditionBuilder);
    
    // 创建联接条件
    const joinCondition: JoinCondition = {
      type: JOIN_TYPE.INNER,
      table,
      alias,
      on: conditionBuilder.getConditions(),
      entityMapping: actualEntityMapping
    };
    
    // 添加联接条件
    this.joinConditions.push(joinCondition);
    
    // 添加参数
    Object.assign(this.parameters, conditionBuilder.getParameters());
    
    return this;
  }

  /**
   * 添加分组字段
   * @param fields 分组字段列表
   */
  public groupBy(...fields: Array<keyof T | string>): this {
    this.groupByFields = fields.map(field => this.processFieldName(field as string));
    return this;
  }

  /**
   * 添加排序条件
   * @param field 排序字段
   * @param direction 排序方向
   */
  public orderBy(field: keyof T | string, direction: OrderDirection = ORDER_DIRECTION.ASC): this {
    const processedField = this.processFieldName(field as string);
    
    this.orderByConditions.push({
      field: processedField,
      direction
    });
    
    return this;
  }

  /**
   * 添加升序排序条件
   * @param field 排序字段
   */
  public orderByAsc(field: keyof T | string): this {
    return this.orderBy(field, ORDER_DIRECTION.ASC);
  }

  /**
   * 添加降序排序条件
   * @param field 排序字段
   */
  public orderByDesc(field: keyof T | string): this {
    return this.orderBy(field, ORDER_DIRECTION.DESC);
  }

  /**
   * 设置结果限制数量
   * @param limit 限制数量
   */
  public limit(limit: number): this {
    this.limitValue = limit;
    return this;
  }

  /**
   * 设置结果偏移数量
   * @param offset 偏移数量
   */
  public offset(offset: number): this {
    this.offsetValue = offset;
    return this;
  }

  /**
   * 设置分页
   * @param page 页码（从1开始）
   * @param pageSize 每页数量
   */
  public page(page: number, pageSize: number): this {
    const pageNum = Math.max(1, page);
    const offset = (pageNum - 1) * pageSize;
    
    this.limitValue = pageSize;
    this.offsetValue = offset;
    
    return this;
  }

  /**
   * 设置为获取单个结果
   */
  public first(): this {
    this.singleResult = true;
    this.limitValue = 1;
    return this;
  }

  /**
   * 设置为获取总数
   */
  public count(): this {
    this.countMode = true;
    return this;
  }

  /**
   * 设置行映射函数
   * @param mapFn 映射函数
   */
  public map<R>(mapFn: (row: Record<string, any>) => R): SelectBuilder<R> {
    const clone = this.clone() as unknown as SelectBuilder<R>;
    clone.mapFunction = mapFn;
    return clone;
  }

  /**
   * 处理字段名，增加对实体映射的支持
   * @param field 字段名
   */
  protected processFieldName(field: string): string {
    let processedField = field;
    
    // 如果有实体映射，转换属性名到字段名
    if (this.entityMapping && this.entityMapping.fields[field]) {
      processedField = this.entityMapping.fields[field].columnName;
    }
    
    // 调用父类处理方法
    return super.processFieldName(processedField);
  }

  /**
   * 构建SQL
   */
  public build(): SqlBuildResult {
    // 应用构建前钩子
    if (this.extensions?.sqlHooks?.beforeBuild) {
      this.extensions.sqlHooks.beforeBuild({
        operationType: this.operationType,
        tableName: this.tableName,
        tableAlias: this.tableAlias,
        fields: this.fields,
        conditions: this.conditions,
        joinConditions: this.joinConditions,
        orderByConditions: this.orderByConditions,
        groupByFields: this.groupByFields,
        limitValue: this.limitValue,
        offsetValue: this.offsetValue,
        countMode: this.countMode,
        distinctMode: this.distinctMode
      });
    }
    
    // 构建SELECT部分
    let sql = 'SELECT ';
    
    // 添加DISTINCT关键字
    if (this.distinctMode) {
      sql += 'DISTINCT ';
    }
    
    // 构建字段部分
    if (this.countMode) {
      sql += 'COUNT(*) AS total';
    } else {
      // 处理表别名
      const tablePrefix = this.tableAlias || this.tableName;
      
      if (this.fields.length === 1 && this.fields[0] === '*') {
        if (this.joinConditions.length > 0) {
          // 如果有联接，使用表前缀限定星号
          sql += `${tablePrefix}.*`;
        } else {
          sql += '*';
        }
      } else {
        sql += this.fields.join(', ');
      }
    }
    
    // 构建FROM部分
    sql += ` FROM ${this.tableName}`;
    
    // 添加表别名
    if (this.tableAlias) {
      sql += ` ${this.tableAlias}`;
    }
    
    // 构建JOIN部分
    if (this.joinConditions.length > 0) {
      for (const joinCondition of this.joinConditions) {
        sql += ` ${joinCondition.type} ${joinCondition.table}`;
        
        if (joinCondition.alias) {
          sql += ` ${joinCondition.alias}`;
        }
        
        if (joinCondition.on) {
          sql += ' ON ';
          
          if (Array.isArray(joinCondition.on)) {
            // 如果是条件数组，使用临时构建器构建条件SQL
            const tempBuilder = new ConditionBuilder<any>(joinCondition.alias, this.extensions);
            tempBuilder['conditions'] = joinCondition.on;
            
            // 不包含WHERE关键字
            const conditionsSql = tempBuilder.buildConditionsSql(false);
            sql += conditionsSql;
          } else {
            // 如果是单个条件
            const condition = joinCondition.on;
            sql += `${condition.field} ${condition.operator} @${condition.parameterName}`;
          }
        }
      }
    }
    
    // 构建WHERE部分
    const whereClause = this.buildConditionsSql();
    if (whereClause) {
      sql += ` ${whereClause}`;
    }
    
    // 构建GROUP BY部分
    if (this.groupByFields.length > 0 && !this.countMode) {
      sql += ` GROUP BY ${this.groupByFields.join(', ')}`;
    }
    
    // 构建ORDER BY部分
    if (this.orderByConditions.length > 0 && !this.countMode) {
      const orderClauses = this.orderByConditions.map(
        order => `${order.field} ${order.direction}`
      );
      sql += ` ORDER BY ${orderClauses.join(', ')}`;
    }
    
    // 构建LIMIT和OFFSET部分
    if (this.limitValue !== undefined && !this.countMode) {
      sql += ` LIMIT ${this.limitValue}`;
      
      if (this.offsetValue !== undefined) {
        sql += ` OFFSET ${this.offsetValue}`;
      }
    }
    
    // 创建结果
    const result: SqlBuildResult = {
      sql,
      params: this.parameters
    };
    
    // 应用构建后钩子
    if (this.extensions?.sqlHooks?.afterBuild) {
      return this.extensions.sqlHooks.afterBuild(result, {
        operationType: this.operationType,
        tableName: this.tableName,
        tableAlias: this.tableAlias
      });
    }
    
    return result;
  }

  /**
   * 将结果映射为指定类型
   * @param rows 数据库返回的行
   */
  public mapToEntity(rows: Record<string, any>[]): QueryResult<T> {
    if (!rows || rows.length === 0) {
      return [] as QueryResult<T>;
    }
    
    // 如果设置了映射函数，使用它
    if (this.mapFunction) {
      return rows.map(this.mapFunction) as QueryResult<T>;
    }
    
    // 如果有实体映射，应用它
    if (this.entityMapping) {
      return rows.map(row => {
        const entity: Record<string, any> = {};
        
        for (const propName in this.entityMapping!.fields) {
          const field = this.entityMapping!.fields[propName];
          const columnName = field.columnName;
          
          // 判断列是否存在，存在则转换，否则使用默认值
          if (row[columnName] !== undefined) {
            entity[propName] = row[columnName];
          } else if (field.defaultValue !== undefined) {
            entity[propName] = field.defaultValue;
          }
        }
        
        return entity as T;
      });
    }
    
    // 如果没有映射，直接返回行
    return rows as QueryResult<T>;
  }

  /**
   * 将单行结果映射为指定类型
   * @param row 数据库返回的行
   */
  public mapToSingleEntity(row: Record<string, any> | undefined): SingleResult<T> {
    if (!row) {
      return undefined;
    }
    
    return this.mapToEntity([row])[0];
  }

  /**
   * 执行查询并返回结果列表
   * @param executor 可选的SQL执行器，如果未提供则使用内部设置的执行器
   */
  public execute(executor?: SqlExecutor): T[] {
    const result = this.build();
    const actualExecutor = executor || this.getExecutor();
    
    if (!actualExecutor) {
      throw new Error('No SQL executor available. Please set an executor using setExecutor() or provide one as parameter.');
    }
    
    const rows = actualExecutor.query(result.sql, result.params);
    return this.mapToEntity(rows);
  }
  
  /**
   * 执行查询并返回单个结果
   * @param executor 可选的SQL执行器，如果未提供则使用内部设置的执行器
   */
  public executeOne(executor?: SqlExecutor): T | undefined {
    // 如果未设置限制为1，则强制设置
    if (!this.singleResult && this.limitValue !== 1) {
      this.first();
    }
    
    const result = this.build();
    const actualExecutor = executor || this.getExecutor();
    
    if (!actualExecutor) {
      throw new Error('No SQL executor available. Please set an executor using setExecutor() or provide one as parameter.');
    }
    
    const row = actualExecutor.queryOne(result.sql, result.params);
    return this.mapToSingleEntity(row);
  }
  
  /**
   * 执行查询并返回总数
   * @param executor 可选的SQL执行器，如果未提供则使用内部设置的执行器
   */
  public executeCount(executor?: SqlExecutor): number {
    // 如果未启用计数模式，则启用
    if (!this.countMode) {
      this.count();
    }
    
    const result = this.build();
    const actualExecutor = executor || this.getExecutor();
    
    if (!actualExecutor) {
      throw new Error('No SQL executor available. Please set an executor using setExecutor() or provide one as parameter.');
    }
    
    const row = actualExecutor.queryOne<{ total: number }>(result.sql, result.params);
    return row?.total || 0;
  }
} 